Linearly Transformed Cosine
#paper #3dcg
特定の分布に対して線形変換を施し、コサイン分布の積分へと帰着させる手法
資料
元論文
https://eheitzresearch.wordpress.com/415-2/
selfshadow氏
https://blog.selfshadow.com/publications/s2016-advances/
https://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_rnd.pdf
https://speakerdeck.com/gam0022/ltc-urp
Implementaion
eric heitz
https://blog.selfshadow.com/sandbox/ltc.html
selfshadow(どうでもいいがEric Heitz氏と同一人物なの?)
https://github.com/selfshadow/ltc_code
LTC shader by gam
https://github.com/gam0022/ShaderPlaygroundURP
kanikama shader by shivaduke
https://github.com/shivaduke28/kanikama/blob/0444c99a3847a74eb1f908717bbe94a8cb97b181/Kanikama/Packages/net.shivaduke28.kanikama/Shaders/KanikamaLTC.hlsl
世に出回っているLUTは一体何?
現論文は BRDF fitting codeのddsファイルとして提供しているやつ
https://scrapbox.io/files/674337fe72697186d9333f2e.png
selfshadow氏が提供している奴(Fresnelを考慮できる)
https://scrapbox.io/files/67434c2700405634bde6c1f4.png
LUTのフィッティング
線形変換Mに対して元のDistributionとcosine分布D0との関係性
https://scrapbox.io/files/67433c82394848f3fa2927c9.png
Dは任意の分布、つまり線形変換で再現できるのであれば何でもOK, (Microfacetとか限らない)
元論文(Eric Heitz氏の実装)
対象のBSDF
https://scrapbox.io/files/67433ba726ec86338590a457.png
縦theta
横roughness
ラフネスが高い、thetaが0に近いほどfittingが甘い感じがある(緑がTarget, ピンクがFitting)
やっぱG項の非線形性が強いんだろうか
https://scrapbox.io/files/67433bdeba6049f9ed02994c.mp4
selfshadow氏のやつ
対象のBSDF
Eric Heitz氏のものと同一・・・?fittingの実装を見ると同様のものをfittingしているっぽい
https://github.com/selfshadow/ltc_code/blob/31e5e96b54f98f33098f8503003119ba2231a1c6/fit/fitLTC.cpp#L370
全く同一のBSDFだった
縦sqrt(1.0 - costheta)
横roughness
何が違うの?
Mapping(cosineベース)
Matrixの正規化の有無
変換を見るとselfshadowの方がクソデカな値を取らないようになっているのがわかる
クソデカだと精度的な問題もあるだろうし、そういう事情かも?
https://blog.selfshadow.com/publications/s2016-advances/s2016_ltc_rnd.pdf
normalizeによって値がクソデカくなって補間がうまく行かないという事情があるらしい
特にグレージング角ではその影響が強いとのこと
rescalingを抜きに作っているっぽい・・・?(どうやってパラメーター減らしてんの)
https://scrapbox.io/files/6744fe59038b1b29d54714e2.mp4
Clipping
https://casual-effects.com/research/McGuire2011Clipping/index.html
Cosine分布上ではy<0の部分は要らない、そのままやると周回積分がおかしくなるのでy=0でクリッピングする処理をする
実装だとQuadを前提としてClipした3~5角形の各頂点を出力する関数がある
やってることは単純
Clipされる場所はQuadの2つの辺
それら辺のz=0となる分割点を求める
あとはどの辺を選ぶのか場合分け
周回積分で使えるように頂点は周回するように配列に格納されている(入れるときもそうすべきなので注意)
分割点の求め方は多分ベクトルの内分点を求めるやつでやる
https://rikeilabo.com/positional-vector
https://scrapbox.io/files/674acf8e46153d3a6765bd5f.png
ただしここでは正規化の処理は入れていない、なのでそのまま出力をポリゴンにするとぶっ飛んだり歪んだりするのが来る
https://scrapbox.io/files/674acf723dc552a145d95550.png
https://scrapbox.io/files/674acf06a4854110ab6a3620.png
実装ではどうせ球面上に投影するので正規化の処理を後々している。
もしClipした正確な頂点が見たかったらこんな感じにClip点を求めればいい
https://scrapbox.io/files/674acfafc05e4c12d70b3263.png
https://scrapbox.io/files/674acfc76da0a8c29b5e14ab.png
https://scrapbox.io/files/674ad6b9801b538472db8f36.png
辺の場合分け
全部の通りでif文分け、Power
ヤコビアンを求めよう
https://scrapbox.io/files/6747276a882e959864d8a3e1.png
立体角のヤコビアン計算はいつも通り変換後の立体角を調べればOK
$ d \omega_0を線形変換した$ \omega_o = M \omegaの立体角$ d\omegaの関係を調べる
立体角と平行な二つのベクトル$ \omega_1,\omega_2を考え、立体角$ d\omega_oはこの二つのベクトルで貼られているとしている。
https://scrapbox.io/files/6747286ecd36623a8eec33ef.png
$ d\omega = d\omega_0 A \frac{\cos{\theta}}{r^2}
という関係がある。Aは返還後の面積、cosは面の向いている方向、rは面の距離。ベクトルとしては次のように表記できる
https://scrapbox.io/files/674729703529fb87a6d316d5.png
Aについて以下の関係が求められる。(がんばりゃこの式が出るはず(確かめてない))
$ M \omega_1 \times M \omega_2 = |M| M^{-T}(\omega_1 \times \omega_2) = |M|M^{-T}\omega_0
cosについて上の式を使えば
$ (\frac{M\omega_0}{||M \omega_0||}) \cdot (\frac{M\omega_1 \times M\omega_2}{||M\omega_1 \times M\omega_2||}) = (\frac{M\omega_0}{||M \omega_0||}) \cdot (\frac{|M|M^{-T}\omega_0}{|||M|M^{-T}\omega_0||})
$ = (\frac{M\omega_0}{||M \omega_0||}) \cdot (\frac{M^{-T}\omega_0}{||M^{-T}\omega_0||}) = (\frac{1}{||M \omega_0|| ||M^{-T}\omega_0||}) M\omega_0 \cdot M^{-T}\omega_0
内積と行列の公式https://ja.wikipedia.org/wiki/転置行列
https://scrapbox.io/files/67472baccd36623a8eec4f40.png
これ使うと
$ M\omega_0 \cdot M^{-T} \omega_0 = \omega_0 \cdot M^T M^{-T} \omega_0 = \omega_0 \cdot I \omega_0 = 1
まとめると
$ d\omega = d\omega_0 A \frac{\cos{\theta}}{r^2} = \frac{|M| |M^{-T}\omega_0| }{||M\omega_o||^2} \frac{1}{||M \omega_0|| ||M^{-T}\omega_0||} = \frac{|M|}{||M\omega_0||^3}
と求められる。つまりは
$ \frac{d\omega}{d\omega_0} = \frac{|M|}{||M\omega_0||^3}
ということになる
reciprocityより
$ \frac{d\omega_0}{d\omega} = \frac{|M^{-1}|}{||M^{-1} \omega_0||^3}
Yeah...
線積分
LambertにおけるArea Lightの積分は次のように求められる
本質的にはAreaLightのエッジに対する周回積分である
https://scrapbox.io/files/674ad8762f06984b3a8c30f5.png
証明について
https://hal.science/hal-01458129/document
Stokesの定理を使って証明したやつ
https://scrapbox.io/files/674ad9100cbc0fb0097900d5.png
https://scrapbox.io/files/674ad9175f87ec76dfde9913.png
https://scrapbox.io/files/674ad92784007b3f8717b2b8.png
線形変換Mとは何か?
そもそもの目的は積分値が変わらない変換みたいなのを考えたい
いわゆる変数変換
それがSpecular分布に近似できたらうれしい
$ \omega' = f(\omega)という変換を考えてみる
$ \int_P D(\omega) d\omega = \int_{P'} D(\omega') \frac{d\omega}{d\omega'} d\omega'
変数変換の関係性から
と求められる
解析可能なのはLambert、ランバートから変数変換したものはランバートとして計算可能
つまり、ランバートから変数変換した分布なら積分が計算可能である
LTCでは変換の仕方に